#pragma once

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <list>
#include <vector>


class IRenderableObject;
class IMesh;
class ICameraImpl;
class CD3DCameraImpl;
class CLight;
class CSkyBox;

class CGraphicsController
{
private:
   IDirect3DDevice9* m_d3Device;
   D3DPRESENT_PARAMETERS m_creationParams;
   D3DCAPS9 m_caps;
   bool m_deviceLost;
   bool m_hardwareTLOn;
   D3DFORMAT m_optimalTextureFormat;
   std::list<CD3DCameraImpl*> m_cameras;
   std::list<CLight*> m_lights;
   CSkyBox* m_skyBox;
   std::wstring m_textureDirPath;

public:
   CGraphicsController(IDirect3DDevice9* d3Device, 
                       D3DPRESENT_PARAMETERS creationParams,
                       D3DCAPS9 caps,
                       float frontBufferAspect,
                       bool hardwareTLOn,
                       D3DFORMAT optimalTextureFormat);
   ~CGraphicsController(void);

   void setTextureDirectoryPath(const std::wstring& path);

   void resizeViewport(unsigned int width, unsigned int height);

   UINT getBackBufferWidth() const {return m_creationParams.BackBufferWidth;}
   UINT getBackBufferHeight() const {return m_creationParams.BackBufferHeight;}

   IDirect3DDevice9& getD3Device();

   UINT getMaxLightsCount() const;

   UINT getSimultaneouslyRenderedTexturesCount() const;

   void render(const std::vector<IRenderableObject*>& renderableObjects);

   IDirect3DVertexBuffer9* createVertexBuffer(UINT length, DWORD usageFlags, DWORD fvf, D3DPOOL memoryPool);

   IDirect3DIndexBuffer9* createIndexBuffer(UINT length, DWORD usageFlags, D3DFORMAT format, D3DPOOL memoryPool);

   IDirect3DTexture9* loadTextureFromFile(const std::wstring& fileName, D3DXIMAGE_INFO* imageInfo = NULL, D3DCOLOR colorKey = 0);

   ICameraImpl& createCamera();

   CLight& createDynamicLight(D3DLIGHTTYPE lightType);

   void setSkyBox(const std::wstring& topFaceTexFileName,
                  const std::wstring& bottomFaceTexFileName,
                  const std::wstring& frontFaceTexFileName,
                  const std::wstring& backFaceTexFileName,
                  const std::wstring& leftFaceTexFileName,
                  const std::wstring& rightFaceTexFileName);

   bool isGraphicsSystemReady();

   void present();

private:
   void initRendererState();

   bool tryRecoveringLostDevice();
};
